#ifndef GF_H
#define GF_H

/*
  Класс поля Галуа с характеристикой поля 2
*/

#include <QObject>

#include "../RScode/source/superheader.h"

struct Deconv {
  QVector<qlonglong> div;
  QVector<qlonglong> mod;
};

class GF : public QObject
{
  Q_OBJECT
private:
  const qlonglong m_p;         // характеристика поля
        qlonglong m_m;         // степень характеристики поля
        qlonglong m_q;         // мощность поля
        qlonglong m_polynom;   // неприводимый полином

  QHash<qlonglong, qlonglong> m_hashTable; // хэш-таблица элементов поля

public:
  explicit GF(qlonglong polynom, QObject *parent = 0);

  // степень примитивного элемента
  qlonglong log(qlonglong x)  const;
  // примитивный элемент в степени
  qlonglong alog(qlonglong s) const;

  // умножение элементов конечного поля
  qlonglong mul(qlonglong x, qlonglong y)  const;
  // деление элементов конечного поля
  qlonglong div(qlonglong x, qlonglong y)  const;
  // сложение элементов конечного поля
  qlonglong plus(qlonglong x, qlonglong y) const;

  // вернуть обратный по умножению элемент
  qlonglong amul(qlonglong x)  const;
  // вернуть обратный по сложению элемент
  qlonglong aplus(qlonglong x) const;

  // возведение в степень элементов конечного поля
  qlonglong power(qlonglong x, qlonglong p) const;

  // сложение полиномов в конечном поле
  QVector<qlonglong> add(QVector<qlonglong> p1, QVector<qlonglong> p2)    const;
  // умножение полиномов в конечном поле
  QVector<qlonglong> conv(QVector<qlonglong> p1, QVector<qlonglong> p2)   const;
  // деление полиномов в конечном поле
  Deconv             deconv(QVector<qlonglong> p1, QVector<qlonglong> p2) const;

  // минимизация длины полинома
  QVector<qlonglong> trunc(QVector<qlonglong> p) const;

  // формальная производная
  QVector<qlonglong> derivative(QVector<qlonglong> poly);
  // подстановка значения в полином
  qlonglong          substitute(QVector<qlonglong> poly, qlonglong x);

  // генерация случайного элемента поля
  qlonglong          genElem() const;
  // генерация случайного полинома заданной длины
  QVector<qlonglong> genPoly(qlonglong len) const;

  // вернуть поле
  QHash<qlonglong, qlonglong> hashTable();

  // представление элемента поля в виде двоичного вектора
  QString toBin(qlonglong x) const;

  // !!!! можно еще сделать
  //  gfpretty — отображение полинома в традиционном формате
  //  gfprimck — проверка полинома в конечном поле на примитивность
  //  gfroots — поиск корней полинома в простом конечном поле
  //  gfsub — вычитание полиномов в конечном поле

  // !!!!!! вернуть m_q
  // !!!!!! вернуть m_polynom
};

#endif // GF_H
